/*
 * MIT License
 *
 * Copyright (c) 2023 北京凯特伟业科技有限公司
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package com.je.bpm.core.json.converter.json.converter;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.base.Strings;
import com.je.bpm.core.json.converter.constants.EditorJsonConstants;
import com.je.bpm.core.json.converter.constants.StencilConstants;
import com.je.bpm.core.json.converter.json.converter.util.CollectionUtils;
import com.je.bpm.core.model.*;
import com.je.bpm.core.model.button.Button;
import com.je.bpm.core.model.button.ProcessButton;
import com.je.bpm.core.model.config.CustomEvent;
import com.je.bpm.core.model.config.ProcessDeployTypeEnum;
import com.je.bpm.core.model.config.ProcessRemindTemplateTypeEnum;
import com.je.bpm.core.model.config.ProcessRemindTypeEnum;
import com.je.bpm.core.model.config.process.*;
import com.je.bpm.core.model.message.Message;
import com.je.bpm.core.model.process.Process;
import com.je.bpm.core.model.signal.Signal;
import com.je.bpm.core.model.task.UserTask;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormatter;
import org.joda.time.format.ISODateTimeFormat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.StringJoiner;

public class BpmnJsonConverterUtil implements EditorJsonConstants, StencilConstants {

    private static final Logger logger = LoggerFactory.getLogger(BpmnJsonConverterUtil.class);

    private static DateTimeFormatter dateTimeFormatter = ISODateTimeFormat.dateTimeParser();
    private static ObjectMapper objectMapper = new ObjectMapper();

    public static ObjectNode createChildShape(String id, String type, double lowerRightX, double lowerRightY, double upperLeftX, double upperLeftY) {
        ObjectNode shapeNode = objectMapper.createObjectNode();
        shapeNode.set(EDITOR_BOUNDS, createBoundsNode(lowerRightX, lowerRightY, upperLeftX, upperLeftY));
        shapeNode.put(EDITOR_SHAPE_ID, id);
        ArrayNode shapesArrayNode = objectMapper.createArrayNode();
        shapeNode.set(EDITOR_CHILD_SHAPES, shapesArrayNode);
        ObjectNode stencilNode = objectMapper.createObjectNode();
        stencilNode.put(EDITOR_STENCIL_ID, type);
        shapeNode.set(EDITOR_STENCIL, stencilNode);
        return shapeNode;
    }

    public static ObjectNode createBoundsNode(double lowerRightX, double lowerRightY, double upperLeftX, double upperLeftY) {
        ObjectNode boundsNode = objectMapper.createObjectNode();
        boundsNode.set(EDITOR_BOUNDS_LOWER_RIGHT, createPositionNode(lowerRightX, lowerRightY));
        boundsNode.set(EDITOR_BOUNDS_UPPER_LEFT, createPositionNode(upperLeftX, upperLeftY));
        return boundsNode;
    }

    public static ObjectNode createPositionNode(double x, double y) {
        ObjectNode positionNode = objectMapper.createObjectNode();
        positionNode.put(EDITOR_BOUNDS_X, x);
        positionNode.put(EDITOR_BOUNDS_Y, y);
        return positionNode;
    }

    public static ObjectNode createResourceNode(String id) {
        ObjectNode resourceNode = objectMapper.createObjectNode();
        resourceNode.put(EDITOR_SHAPE_ID, id);
        return resourceNode;
    }

    public static String getStencilId(JsonNode objectNode) {
        String stencilId = null;
        JsonNode stencilNode = objectNode.get(EDITOR_STENCIL);
        if (stencilNode != null && stencilNode.get(EDITOR_STENCIL_ID) != null) {
            stencilId = stencilNode.get(EDITOR_STENCIL_ID).asText();
        }
        return stencilId;
    }

    public static String getKaiteStencilId(String stencilId) {
        if (stencilId.equals(STENCIL_EVENT_START_KAITE_NONE)) {
            return STENCIL_EVENT_START_NONE;
        } else if (stencilId.equals(STENCIL_EVENT_END_KAITE_NONE)) {
            return STENCIL_EVENT_END_NONE;
        } else if (stencilId.equals(STENCIL_SEQUENCE_KAITE_FLOW)) {
            return STENCIL_SEQUENCE_FLOW;
        } else if (stencilId.equals(STENCIL_GATEWAY_KAITE_FORK__INCLUSIVE) || stencilId.equals(STENCIL_GATEWAY_KAITE_JOIN_INCLUSIVE)) {
            return STENCIL_GATEWAY_INCLUSIVE;
        }
        return stencilId;
    }

    public static String getElementId(JsonNode objectNode) {
        String elementId = null;
        if (StringUtils.isNotEmpty(getPropertyValueAsString(PROPERTY_OVERRIDE_ID, objectNode))) {
            elementId = getPropertyValueAsString(PROPERTY_OVERRIDE_ID, objectNode).trim();
        } else {
            elementId = objectNode.get(EDITOR_SHAPE_ID).asText();
        }

        return elementId;
    }

    /**
     * 写入流程按钮信息
     *
     * @param buttons
     * @param propertiesNode
     */
    public static void convertProcessButtonsToJson(List<ProcessButton> buttons, ObjectNode propertiesNode) {
        ArrayNode processButtonArrayNode = objectMapper.createArrayNode();
        ObjectNode eachNode;
        for (Button eachButton : buttons) {
            eachNode = objectMapper.createObjectNode();
            eachNode.put(PROPERTY_BUTTON_ID, eachButton.getId());
            eachNode.put(PROPERTY_BUTTON_CODE, eachButton.getCode());
            eachNode.put(PROPERTY_BUTTON_NAME, eachButton.getName());
            eachNode.put(PROPERTY_BUTTON_CUSTOMIZE_NAME, eachButton.getCustomizeName());
            eachNode.put(PROPERTY_BUTTON_CUSTOMIZE_COMMENTS, eachButton.getCustomizeComments());
            eachNode.put(PROPERTY_BUTTON_OPERATION, eachButton.getOperationId());
            eachNode.put(PROPERTY_BUTTON_BACKEND_LISTENERS, eachButton.getBackendListeners());
            eachNode.put(PROPERTY_BUTTON_APP_LISTENERS, eachButton.getAppListeners());
            eachNode.put(PROPERTY_BUTTON_PC_LISTENERS, eachButton.getPcListeners());
            eachNode.put(PROPERTY_PROCESS_BUTTON_DISLAY_WHEN_NOT_STARTED, "");
            eachNode.put(PROPERTY_TASK_BUTTON_DISLAY_EXPRESSION, eachButton.getDisplayExpressionWhenStarted());
            processButtonArrayNode.add(eachNode);
        }
        propertiesNode.set(PROPERTY_PROCESS_BUTTON_CONFIG, processButtonArrayNode);
    }

    /**
     * 写入流程拓展配置
     *
     * @param processBasicConfig
     */
    public static void convertProcessBasicConfigToJson(ProcessBasicConfigImpl processBasicConfig, ObjectNode propertiesNode) {
        ObjectNode processBasicConfigNode = objectMapper.createObjectNode();
        processBasicConfigNode.put(PROPERTY_FUNC_CODE, processBasicConfig.getFuncCode());
        processBasicConfigNode.put(PROPERTY_FUNC_NAME, processBasicConfig.getFuncName());
        processBasicConfigNode.put(PROPERTY_FUNC_ID, processBasicConfig.getFuncId());
        processBasicConfigNode.put(PROPERTY_FUNC_TABLE_CODE, processBasicConfig.getTableCode());
        processBasicConfigNode.put(PROPERTY_FUNC_ATTACHED_FUNC_CODES, processBasicConfig.getAttachedFuncCodes());
        processBasicConfigNode.put(PROPERTY_FUNC_ATTACHED_FUNC_NAMES, processBasicConfig.getAttachedFuncNames());
        processBasicConfigNode.put(PROPERTY_FUNC_ATTACHED_FUNC_IDS, processBasicConfig.getAttachedFuncIds());
        processBasicConfigNode.put(PROPERTY_FUNC_CONTENT_MODULE, processBasicConfig.getContentModule());
        processBasicConfigNode.put(PROPERTY_FUNC_PROCESS_CLASSIFICATION_CODE, processBasicConfig.getProcessClassificationCode());
        processBasicConfigNode.put(PROPERTY_FUNC_PROCESS_CLASSIFICATION_NAME, processBasicConfig.getProcessClassificationName());
        processBasicConfigNode.put(PROPERTY_FUNC_PROCESS_CLASSIFICATION_ID, processBasicConfig.getProcessClassificationId());
        processBasicConfigNode.put(PROPERTY_PROCESS_MODE, processBasicConfig.getDeploymentEnvironment().toString());
        propertiesNode.set(PROPERTY_PROCESS_BASIC_CONFIG, processBasicConfigNode);
    }

    /**
     * 写入流程拓展配置
     *
     * @param extendedConfigurationConfig
     */
    public static void convertProcessExtendedConfigToJson(ExtendedConfigurationConfigImpl extendedConfigurationConfig, ObjectNode propertiesNode) {
        ObjectNode processBasicConfigNode = objectMapper.createObjectNode();
        processBasicConfigNode.put(PROPERTY_PROCESS_CANSPONSOR, convertBooleanToIntJson(extendedConfigurationConfig.isCanSponsor()));
        processBasicConfigNode.put(PROPERTY_PROCESS_CANRETRIEVE, convertBooleanToIntJson(extendedConfigurationConfig.isCanRetrieve()));
        processBasicConfigNode.put(PROPERTY_PROCESS_RETURN, convertBooleanToIntJson(extendedConfigurationConfig.isCanReturn()));
        processBasicConfigNode.put(PROPERTY_PROCESS_CANURGED, convertBooleanToIntJson(extendedConfigurationConfig.isCanUrged()));
        processBasicConfigNode.put(PROPERTY_PROCESS_CANCANCEL, convertBooleanToIntJson(extendedConfigurationConfig.isCanCancel()));
        processBasicConfigNode.put(PROPERTY_PROCESS_CANINVALID, convertBooleanToIntJson(extendedConfigurationConfig.isCanInvalid()));
        processBasicConfigNode.put(PROPERTY_PROCESS_CANTRANSFER, convertBooleanToIntJson(extendedConfigurationConfig.isCanTransfer()));
        processBasicConfigNode.put(PROPERTY_PROCESS_CANDELEGATE, convertBooleanToIntJson(extendedConfigurationConfig.isCanDelegate()));
        processBasicConfigNode.put(PROPERTY_PROCESS_EASY_LAUNCH, convertBooleanToIntJson(extendedConfigurationConfig.isEasyLaunch()));
        processBasicConfigNode.put(PROPERTY_PROCESS_SIMPLE_APPROVAL, convertBooleanToIntJson(extendedConfigurationConfig.isSimpleApproval()));
        processBasicConfigNode.put(PROPERTY_PROCESS_HIDE_STATE_INFO, convertBooleanToIntJson(extendedConfigurationConfig.isHideStateInfo()));
        processBasicConfigNode.put(PROPERTY_PROCESS_HIDE_TIME_INFO, convertBooleanToIntJson(extendedConfigurationConfig.isHideTimeInfo()));
        propertiesNode.set(PROPERTY_PROCESS_EXTENDED_CONFIG, processBasicConfigNode);
    }

    /**
     * 写入流程启动配置
     *
     * @param startupSettingsConfig
     */
    public static void convertProcessStartUpConfigToJson(StartupSettingsConfigImpl startupSettingsConfig, ObjectNode propertiesNode) {
        ObjectNode processBasicConfigNode = objectMapper.createObjectNode();
        processBasicConfigNode.put(PROPERTY_PROCESS_CANEVERYONESTART, convertBooleanToIntJson(startupSettingsConfig.isCanEveryoneStart()));
        processBasicConfigNode.put(PROPERTY_PROCESS_CANEVERYONE_ROLES_ID, startupSettingsConfig.getCanEveryoneRolesId());
        processBasicConfigNode.put(PROPERTY_PROCESS_CANEVERYONE_ROLES_NAME, startupSettingsConfig.getCanEveryoneRolesName());
        processBasicConfigNode.put(PROPERTY_PROCESS_START_EXPRESSION, startupSettingsConfig.getStartExpression());
        processBasicConfigNode.put(PROPERTY_PROCESS_START_EXPRESSION_FN, startupSettingsConfig.getStartExpressionFn());
        propertiesNode.set(PROPERTY_PROCESS_STARTUP_CONFIG, processBasicConfigNode);
    }

    /**
     * 写入流程自定义事件
     *
     * @param customEventList
     */
    public static void convertProcessCustomEventListenersConfigToJson(List<CustomEvent> customEventList, ObjectNode propertiesNode) {
        ArrayNode processCustomEventListArrayNode = objectMapper.createArrayNode();
        ObjectNode eachNode;
        for (CustomEvent customEvent : customEventList) {
            eachNode = objectMapper.createObjectNode();
            eachNode.put(CUSTOM_EVENT_TYPE_NAME, customEvent.getCustomeEventType().getName());
            eachNode.put(CUSTOM_EVENT_TYPE_CODE, customEvent.getCustomeEventType().toString());
            eachNode.put(CUSTOM_EVENT_EXECUTION_STRATEGY_NAME, customEvent.getExecutionStrategy().getName());
            eachNode.put(CUSTOM_EVENT_EXECUTION_STRATEGY_CODE, customEvent.getExecutionStrategy().toString());
            eachNode.put(CUSTOM_EVENT_ASSIGNMENT_FIELD_CONFIGURATION, customEvent.getAssignmentFieldConfiguration());
            eachNode.put(CUSTOM_EVENT_SERVICE_NAME, customEvent.getServiceName());
            eachNode.put(CUSTOM_EVENT_METHOD, customEvent.getMethod());
            eachNode.put(CUSTOM_EVENT_EXISTENCEPARAMETER, customEvent.getExistenceParameter());
            processCustomEventListArrayNode.add(eachNode);
        }
        propertiesNode.set(PROPERTY_PROCESS_CUSTOM_EVENT_LISTENERS_CONFIG, processCustomEventListArrayNode);
    }

    public static void convertMessagesToJson(MessageSettingConfigImpl messageSettingConfig, ObjectNode propertiesNode) {
        ObjectNode messageSettingNode = objectMapper.createObjectNode();
        List<ProcessRemindTemplate> remindTemplateList = messageSettingConfig.getMessageDefinitions();
        ObjectNode messageDefinitionsNode = objectMapper.createObjectNode();
        for (ProcessRemindTemplate template : remindTemplateList) {
            messageDefinitionsNode.put(template.getType().toString(), template.getTemplate());
        }
        List<ProcessRemindTypeEnum> list = messageSettingConfig.getMessages();
        StringJoiner joiner = new StringJoiner(",");
        list.stream().map(Enum::toString).forEach(joiner::add);
        String processRemindTypes = joiner.toString();

        messageSettingNode.set(PROPERTY_PROCESS_MESSAGE_DEFINITIONS, messageDefinitionsNode);
        messageSettingNode.put(PROPERTY_PROCESS_MESSAGE_MESSAGES, processRemindTypes);
        propertiesNode.set(PROPERTY_PROCESS_MESSAGE_SETTING, messageSettingNode);
    }

    public static void convertListenersToJson(List<ActivitiListener> listeners, boolean isExecutionListener, ObjectNode propertiesNode) {
        String propertyName = null;
        String valueName = null;
        if (isExecutionListener) {
            propertyName = PROPERTY_EXECUTION_LISTENERS;
            valueName = "executionListeners";
        } else {
            propertyName = PROPERTY_TASK_LISTENERS;
            valueName = "taskListeners";
        }

        ObjectNode listenersNode = objectMapper.createObjectNode();
        ArrayNode itemsNode = objectMapper.createArrayNode();
        for (ActivitiListener listener : listeners) {
            ObjectNode propertyItemNode = objectMapper.createObjectNode();
            propertyItemNode.put(PROPERTY_LISTENER_EVENT, listener.getEvent());
            if (ImplementationType.IMPLEMENTATION_TYPE_CLASS.equals(listener.getImplementationType())) {
                propertyItemNode.put(PROPERTY_LISTENER_CLASS_NAME, listener.getImplementation());
            } else if (ImplementationType.IMPLEMENTATION_TYPE_EXPRESSION.equals(listener.getImplementationType())) {
                propertyItemNode.put(PROPERTY_LISTENER_EXPRESSION, listener.getImplementation());
            } else if (ImplementationType.IMPLEMENTATION_TYPE_DELEGATEEXPRESSION.equals(listener.getImplementationType())) {
                propertyItemNode.put(PROPERTY_LISTENER_DELEGATE_EXPRESSION, listener.getImplementation());
            }
            if (CollectionUtils.isNotEmpty(listener.getFieldExtensions())) {
                ArrayNode fieldsArray = objectMapper.createArrayNode();
                for (FieldExtension fieldExtension : listener.getFieldExtensions()) {
                    ObjectNode fieldNode = objectMapper.createObjectNode();
                    fieldNode.put(PROPERTY_FIELD_NAME, fieldExtension.getFieldName());
                    if (StringUtils.isNotEmpty(fieldExtension.getStringValue())) {
                        fieldNode.put(PROPERTY_FIELD_STRING_VALUE, fieldExtension.getStringValue());
                    }
                    if (StringUtils.isNotEmpty(fieldExtension.getExpression())) {
                        fieldNode.put(PROPERTY_FIELD_EXPRESSION, fieldExtension.getExpression());
                    }
                    fieldsArray.add(fieldNode);
                }
                propertyItemNode.set(PROPERTY_LISTENER_FIELDS, fieldsArray);
            }
            itemsNode.add(propertyItemNode);
        }
        listenersNode.set(valueName, itemsNode);
        propertiesNode.set(propertyName, listenersNode);
    }

    public static void convertEventListenersToJson(List<EventListener> listeners, ObjectNode propertiesNode) {
        ObjectNode listenersNode = objectMapper.createObjectNode();
        ArrayNode itemsNode = objectMapper.createArrayNode();
        for (EventListener listener : listeners) {
            ObjectNode propertyItemNode = objectMapper.createObjectNode();

            if (StringUtils.isNotEmpty(listener.getEvents())) {
                ArrayNode eventArrayNode = objectMapper.createArrayNode();
                String[] eventArray = listener.getEvents().split(",");
                for (String eventValue : eventArray) {
                    if (StringUtils.isNotEmpty(eventValue.trim())) {
                        ObjectNode eventNode = objectMapper.createObjectNode();
                        eventNode.put(PROPERTY_EVENTLISTENER_EVENT, eventValue.trim());
                        eventArrayNode.add(eventNode);
                    }
                }
                propertyItemNode.put(PROPERTY_EVENTLISTENER_EVENT, listener.getEvents());
                propertyItemNode.set(PROPERTY_EVENTLISTENER_EVENTS, eventArrayNode);
            }

            String implementationText = null;
            if (ImplementationType.IMPLEMENTATION_TYPE_CLASS.equals(listener.getImplementationType())) {
                propertyItemNode.put(PROPERTY_EVENTLISTENER_CLASS_NAME, listener.getImplementation());
                implementationText = listener.getImplementation();

            } else if (ImplementationType.IMPLEMENTATION_TYPE_DELEGATEEXPRESSION.equals(listener.getImplementationType())) {
                propertyItemNode.put(PROPERTY_EVENTLISTENER_DELEGATE_EXPRESSION, listener.getImplementation());
                implementationText = listener.getImplementation();

            } else if (ImplementationType.IMPLEMENTATION_TYPE_THROW_ERROR_EVENT.equals(listener.getImplementationType())) {
                propertyItemNode.put(PROPERTY_EVENTLISTENER_RETHROW_EVENT, true);
                propertyItemNode.put(PROPERTY_EVENTLISTENER_RETHROW_TYPE, "error");
                propertyItemNode.put(PROPERTY_EVENTLISTENER_ERROR_CODE, listener.getImplementation());
                implementationText = "Rethrow as error " + listener.getImplementation();

            } else if (ImplementationType.IMPLEMENTATION_TYPE_THROW_MESSAGE_EVENT.equals(listener.getImplementationType())) {
                propertyItemNode.put(PROPERTY_EVENTLISTENER_RETHROW_EVENT, true);
                propertyItemNode.put(PROPERTY_EVENTLISTENER_RETHROW_TYPE, "message");
                propertyItemNode.put(PROPERTY_EVENTLISTENER_MESSAGE_NAME, listener.getImplementation());
                implementationText = "Rethrow as message " + listener.getImplementation();

            } else if (ImplementationType.IMPLEMENTATION_TYPE_THROW_SIGNAL_EVENT.equals(listener.getImplementationType())) {
                propertyItemNode.put(PROPERTY_EVENTLISTENER_RETHROW_EVENT, true);
                propertyItemNode.put(PROPERTY_EVENTLISTENER_RETHROW_TYPE, "signal");
                propertyItemNode.put(PROPERTY_EVENTLISTENER_SIGNAL_NAME, listener.getImplementation());
                implementationText = "Rethrow as signal " + listener.getImplementation();

            } else if (ImplementationType.IMPLEMENTATION_TYPE_THROW_GLOBAL_SIGNAL_EVENT.equals(listener.getImplementationType())) {
                propertyItemNode.put(PROPERTY_EVENTLISTENER_RETHROW_EVENT, true);
                propertyItemNode.put(PROPERTY_EVENTLISTENER_RETHROW_TYPE, "globalSignal");
                propertyItemNode.put(PROPERTY_EVENTLISTENER_SIGNAL_NAME, listener.getImplementation());
                implementationText = "Rethrow as signal " + listener.getImplementation();
            }

            if (StringUtils.isNotEmpty(implementationText)) {
                propertyItemNode.put(PROPERTY_EVENTLISTENER_IMPLEMENTATION, implementationText);
            }

            if (StringUtils.isNotEmpty(listener.getEntityType())) {
                propertyItemNode.put(PROPERTY_EVENTLISTENER_ENTITY_TYPE, listener.getEntityType());
            }

            itemsNode.add(propertyItemNode);
        }

        listenersNode.set(PROPERTY_EVENTLISTENER_VALUE, itemsNode);
        propertiesNode.set(PROPERTY_EVENT_LISTENERS, listenersNode);
    }

    public static void convertSignalDefinitionsToJson(BpmnModel bpmnModel, ObjectNode propertiesNode) {
        if (bpmnModel.getSignals() != null) {
            ArrayNode signalDefinitions = objectMapper.createArrayNode();
            for (Signal signal : bpmnModel.getSignals()) {
                ObjectNode signalNode = signalDefinitions.addObject();
                signalNode.put(PROPERTY_SIGNAL_DEFINITION_ID, signal.getId());
                signalNode.put(PROPERTY_SIGNAL_DEFINITION_NAME, signal.getName());
                signalNode.put(PROPERTY_SIGNAL_DEFINITION_SCOPE, signal.getScope());
            }
            propertiesNode.set(PROPERTY_SIGNAL_DEFINITIONS, signalDefinitions);
        }
    }

    public static void convertMessagesToJson(BpmnModel bpmnModel, ObjectNode propertiesNode) {
        if (bpmnModel.getMessages() != null) {
            ArrayNode messageDefinitions = objectMapper.createArrayNode();
            for (Message message : bpmnModel.getMessages()) {
                ObjectNode messageNode = messageDefinitions.addObject();
                messageNode.put(PROPERTY_MESSAGE_DEFINITION_ID, message.getId());
                messageNode.put(PROPERTY_MESSAGE_DEFINITION_NAME, message.getName());
            }
            propertiesNode.set(PROPERTY_MESSAGE_DEFINITIONS, messageDefinitions);
        }
    }

    /**
     * 解析流程按钮
     *
     * @param objectNode
     * @param process
     */
    public static void convertJsonToProcessButtons(JsonNode objectNode, Process process) {
        ArrayNode arrayNode = (ArrayNode) getProperty(PROPERTY_PROCESS_BUTTON_CONFIG, objectNode);
        if (arrayNode == null || arrayNode.size() == 0) {
            return;
        }
        for (JsonNode eachNode : arrayNode) {
            for (Button button : process.getButtons().getButtons()) {
                if (button.getCode().equalsIgnoreCase(getValueAsString(PROPERTY_BUTTON_CODE, eachNode))) {
                    button.setCustomizeName(getValueAsString(PROPERTY_BUTTON_CUSTOMIZE_NAME, eachNode));
                    button.setCustomizeComments(getValueAsString(PROPERTY_BUTTON_CUSTOMIZE_COMMENTS, eachNode));
                    button.setAppListeners(getValueAsString(PROPERTY_BUTTON_APP_LISTENERS, eachNode));
                    button.setBackendListeners(getValueAsString(PROPERTY_BUTTON_BACKEND_LISTENERS, eachNode));
                    button.setPcListeners(getValueAsString(PROPERTY_BUTTON_PC_LISTENERS, eachNode));
                }
            }
        }
    }

    /**
     * 解析流程基础配置
     *
     * @param objectNode
     * @param process
     */
    public static void convertJsonToProcessBasic(JsonNode objectNode, Process process) {
        //基础配置
        convertJsonToProcessBasicConfig(objectNode, process);
        //拓展配置
        convertJsonToExtendedConfiguration(objectNode, process);
        //启动
        convertJsonToStartupSettings(objectNode, process);
        //自定义事件
        convertJsonToCustomEventListeners(objectNode, process);
        //消息
        convertJsonToMessageSetting(objectNode, process);
    }

    private static void convertJsonToProcessBasicConfig(JsonNode objectNode, Process process) {
        JsonNode processBasicConfigNode = getProperty(PROPERTY_PROCESS_BASIC_CONFIG, objectNode);
        ProcessBasicConfigImpl processBasicConfig = process.getProcessConfig();
        processBasicConfig.setFuncCode(getValueAsString(PROPERTY_FUNC_CODE, processBasicConfigNode));
        processBasicConfig.setFuncName(getValueAsString(PROPERTY_FUNC_NAME, processBasicConfigNode));
        processBasicConfig.setFuncId(getValueAsString(PROPERTY_FUNC_ID, processBasicConfigNode));
        processBasicConfig.setTableCode(getValueAsString(PROPERTY_FUNC_TABLE_CODE, processBasicConfigNode));
        processBasicConfig.setAttachedFuncNames(getValueAsString(PROPERTY_FUNC_ATTACHED_FUNC_IDS, processBasicConfigNode));
        processBasicConfig.setAttachedFuncCodes(getValueAsString(PROPERTY_FUNC_ATTACHED_FUNC_NAMES, processBasicConfigNode));
        processBasicConfig.setAttachedFuncIds(getValueAsString(PROPERTY_FUNC_ATTACHED_FUNC_IDS, processBasicConfigNode));
        processBasicConfig.setContentModule(getValueAsString(PROPERTY_FUNC_CONTENT_MODULE, processBasicConfigNode));
        processBasicConfig.setProcessClassificationCode(getValueAsString(PROPERTY_FUNC_PROCESS_CLASSIFICATION_CODE, processBasicConfigNode));
        processBasicConfig.setProcessClassificationId(getValueAsString(PROPERTY_FUNC_PROCESS_CLASSIFICATION_ID, processBasicConfigNode));
        processBasicConfig.setProcessClassificationName(getValueAsString(PROPERTY_FUNC_PROCESS_CLASSIFICATION_NAME, processBasicConfigNode));
        processBasicConfig.setDeploymentEnvironment(ProcessDeployTypeEnum.getMode(getValueAsString(PROPERTY_PROCESS_MODE, processBasicConfigNode)));
        process.setProcessConfig(processBasicConfig);
    }

    private static void convertJsonToExtendedConfiguration(JsonNode objectNode, Process process) {
        JsonNode extendedNode = getProperty(PROPERTY_PROCESS_EXTENDED_CONFIG, objectNode);
        ExtendedConfigurationConfigImpl extendedConfigurationConfig = new ExtendedConfigurationConfigImpl();
        extendedConfigurationConfig.setCanSponsor(getValueAsBoolean(PROPERTY_PROCESS_CANSPONSOR, extendedNode));
        extendedConfigurationConfig.setCanRetrieve(getValueAsBoolean(PROPERTY_PROCESS_CANRETRIEVE, extendedNode));
        extendedConfigurationConfig.setCanReturn(getValueAsBoolean(PROPERTY_PROCESS_RETURN, extendedNode));
        extendedConfigurationConfig.setCanUrged(getValueAsBoolean(PROPERTY_PROCESS_CANURGED, extendedNode));
        extendedConfigurationConfig.setCanCancel(getValueAsBoolean(PROPERTY_PROCESS_CANCANCEL, extendedNode));
        extendedConfigurationConfig.setCanInvalid(getValueAsBoolean(PROPERTY_PROCESS_CANINVALID, extendedNode));
        extendedConfigurationConfig.setCanTransfer(getValueAsBoolean(PROPERTY_PROCESS_CANTRANSFER, extendedNode));
        extendedConfigurationConfig.setCanDelegate(getValueAsBoolean(PROPERTY_PROCESS_CANDELEGATE, extendedNode));
        extendedConfigurationConfig.setEasyLaunch(getValueAsBoolean(PROPERTY_PROCESS_EASY_LAUNCH, extendedNode));
        extendedConfigurationConfig.setSimpleApproval(getValueAsBoolean(PROPERTY_PROCESS_SIMPLE_APPROVAL, extendedNode));
        extendedConfigurationConfig.setHideStateInfo(getValueAsBoolean(PROPERTY_PROCESS_HIDE_STATE_INFO, extendedNode));
        extendedConfigurationConfig.setHideTimeInfo(getValueAsBoolean(PROPERTY_PROCESS_HIDE_TIME_INFO, extendedNode));
        process.setExtendedConfiguration(extendedConfigurationConfig);
    }

    private static void convertJsonToStartupSettings(JsonNode objectNode, Process process) {
        JsonNode extendedNode = getProperty(PROPERTY_PROCESS_STARTUP_CONFIG, objectNode);
        StartupSettingsConfigImpl startupSettingsConfig = new StartupSettingsConfigImpl();
        startupSettingsConfig.setCanEveryoneStart(getValueAsBoolean(PROPERTY_PROCESS_CANEVERYONESTART, extendedNode));
        startupSettingsConfig.setCanEveryoneRolesId(getValueAsString(PROPERTY_PROCESS_CANEVERYONE_ROLES_ID, extendedNode));
        startupSettingsConfig.setCanEveryoneRolesName(getValueAsString(PROPERTY_PROCESS_CANEVERYONE_ROLES_NAME, extendedNode));
        startupSettingsConfig.setStartExpression(getValueAsString(PROPERTY_PROCESS_START_EXPRESSION, extendedNode));
        startupSettingsConfig.setStartExpressionFn(getValueAsString(PROPERTY_PROCESS_START_EXPRESSION_FN, extendedNode));
        process.setStartupSettings(startupSettingsConfig);
    }

    private static void convertJsonToCustomEventListeners(JsonNode objectNode, Process process) {
        ArrayNode arrayNode = (ArrayNode) getProperty(PROPERTY_PROCESS_CUSTOM_EVENT_LISTENERS_CONFIG, objectNode);
        if (arrayNode == null) {
            return;
        }
        List<CustomEvent> customEventListeners = new ArrayList<>();
        for (JsonNode jsonNode : arrayNode) {
            CustomEvent customEvent = new CustomEvent();
            customEvent.setType(CustomEvent.CustomEventEnum.getEventByCode(getValueAsString(CUSTOM_EVENT_TYPE_CODE, jsonNode)));
            customEvent.setExecutionStrategy(CustomEvent.CustomExecutionStrategyEnum.getExecutionStrategyByCode(getValueAsString(CUSTOM_EVENT_EXECUTION_STRATEGY_CODE, jsonNode)));
            customEvent.setAssignmentFieldConfiguration(getValueAsString(CUSTOM_EVENT_ASSIGNMENT_FIELD_CONFIGURATION, jsonNode));
            customEvent.setServiceName(getValueAsString(CUSTOM_EVENT_SERVICE_NAME, jsonNode));
            customEvent.setMethod(getValueAsString(CUSTOM_EVENT_METHOD, jsonNode));
            customEvent.setExistenceParameter(getValueAsBoolean(CUSTOM_EVENT_EXISTENCEPARAMETER, jsonNode));
            customEventListeners.add(customEvent);
        }
        process.setCustomEventListeners(customEventListeners);
    }

    private static void convertJsonToMessageSetting(JsonNode objectNode, Process process) {
        JsonNode messageConfig = getProperty(PROPERTY_PROCESS_MESSAGE_SETTING, objectNode);
        MessageSettingConfigImpl messageSettingConfig = new MessageSettingConfigImpl();
        List<ProcessRemindTemplate> messageDefinitions = new ArrayList<>();
        JsonNode messageDefinitionsNode = messageConfig.get(PROPERTY_PROCESS_MESSAGE_DEFINITIONS);

        if (messageDefinitionsNode != null) {
            Iterator<String> definitionsFields = messageDefinitionsNode.fieldNames();
            for (Iterator<String> it = definitionsFields; it.hasNext(); ) {
                String field = it.next();
                ProcessRemindTemplate processRemindTemplate = new ProcessRemindTemplate();
                processRemindTemplate.setType(ProcessRemindTemplateTypeEnum.getType(field));
                processRemindTemplate.setTemplate(getValueAsString(field, messageDefinitionsNode));
                messageDefinitions.add(processRemindTemplate);
            }
            messageSettingConfig.setMessageDefinitions(messageDefinitions);
        }

        List<ProcessRemindTypeEnum> messages = new ArrayList<>();
        String messagesNodeValue = getValueAsString(PROPERTY_PROCESS_MESSAGE_MESSAGES, messageConfig);
        if (!Strings.isNullOrEmpty(messagesNodeValue)) {
            String[] messagesValue = messagesNodeValue.split(",");
            for (String value : messagesValue) {
                messages.add(ProcessRemindTypeEnum.getType(value));
            }
        }
        messageSettingConfig.setMessages(messages);
        process.setMessageSetting(messageSettingConfig);
    }


    public static void convertJsonToListeners(JsonNode objectNode, BaseElement element) {
        JsonNode executionListenersNode = getProperty(PROPERTY_EXECUTION_LISTENERS, objectNode);
        if (executionListenersNode != null) {
            executionListenersNode = validateIfNodeIsTextual(executionListenersNode);
            JsonNode listenersNode = executionListenersNode.get("executionListeners");
            parseListeners(listenersNode, element, false);
        }

        if (element instanceof UserTask) {
            JsonNode taskListenersNode = getProperty(PROPERTY_TASK_LISTENERS, objectNode);
            if (taskListenersNode != null) {
                taskListenersNode = validateIfNodeIsTextual(taskListenersNode);
                JsonNode listenersNode = taskListenersNode.get("taskListeners");
                parseListeners(listenersNode, element, true);
            }
        }
    }

    public static void convertJsonToMessages(JsonNode objectNode, BpmnModel element) {
        JsonNode messagesNode = getProperty(PROPERTY_MESSAGE_DEFINITIONS, objectNode);
        if (messagesNode != null) {
            messagesNode = validateIfNodeIsTextual(messagesNode);
            parseMessages(messagesNode, element);
        }
    }

    protected static void parseListeners(JsonNode listenersNode, BaseElement element, boolean isTaskListener) {
        if (listenersNode == null) {
            return;
        }
        listenersNode = validateIfNodeIsTextual(listenersNode);
        for (JsonNode listenerNode : listenersNode) {
            listenerNode = validateIfNodeIsTextual(listenerNode);
            JsonNode eventNode = listenerNode.get(PROPERTY_LISTENER_EVENT);
            if (eventNode != null && !eventNode.isNull() && StringUtils.isNotEmpty(eventNode.asText())) {

                ActivitiListener listener = new ActivitiListener();
                listener.setEvent(eventNode.asText());
                if (StringUtils.isNotEmpty(getValueAsString(PROPERTY_LISTENER_CLASS_NAME, listenerNode))) {
                    listener.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_CLASS);
                    listener.setImplementation(getValueAsString(PROPERTY_LISTENER_CLASS_NAME, listenerNode));
                } else if (StringUtils.isNotEmpty(getValueAsString(PROPERTY_LISTENER_EXPRESSION, listenerNode))) {
                    listener.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_EXPRESSION);
                    listener.setImplementation(getValueAsString(PROPERTY_LISTENER_EXPRESSION, listenerNode));
                } else if (StringUtils.isNotEmpty(getValueAsString(PROPERTY_LISTENER_DELEGATE_EXPRESSION, listenerNode))) {
                    listener.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_DELEGATEEXPRESSION);
                    listener.setImplementation(getValueAsString(PROPERTY_LISTENER_DELEGATE_EXPRESSION, listenerNode));
                }

                JsonNode fieldsNode = listenerNode.get(PROPERTY_LISTENER_FIELDS);
                if (fieldsNode != null) {
                    for (JsonNode fieldNode : fieldsNode) {
                        JsonNode nameNode = fieldNode.get(PROPERTY_FIELD_NAME);
                        if (nameNode != null && !nameNode.isNull() && StringUtils.isNotEmpty(nameNode.asText())) {
                            FieldExtension fieldExtension = new FieldExtension();
                            fieldExtension.setFieldName(nameNode.asText());
                            fieldExtension.setStringValue(getValueAsString(PROPERTY_FIELD_STRING_VALUE, fieldNode));
                            if (StringUtils.isEmpty(fieldExtension.getStringValue())) {
                                fieldExtension.setStringValue(getValueAsString(PROPERTY_FIELD_STRING, fieldNode));
                            }
                            if (StringUtils.isEmpty(fieldExtension.getStringValue())) {
                                fieldExtension.setExpression(getValueAsString(PROPERTY_FIELD_EXPRESSION, fieldNode));
                            }
                            listener.getFieldExtensions().add(fieldExtension);
                        }
                    }
                }

                if (element instanceof Process) {
                    ((Process) element).getExecutionListeners().add(listener);
                } else if (element instanceof SequenceFlow) {
                    ((SequenceFlow) element).getExecutionListeners().add(listener);
                } else if (element instanceof UserTask) {
                    if (isTaskListener) {
                        ((UserTask) element).getTaskListeners().add(listener);
                    } else {
                        ((UserTask) element).getExecutionListeners().add(listener);
                    }
                } else if (element instanceof FlowElement) {
                    ((FlowElement) element).getExecutionListeners().add(listener);
                }
            }
        }
    }

    protected static void parseMessages(JsonNode messagesNode, BpmnModel element) {
        if (messagesNode == null) {
            return;
        }

        for (JsonNode messageNode : messagesNode) {

            Message message = new Message();

            String messageId = getValueAsString(PROPERTY_MESSAGE_DEFINITION_ID, messageNode);
            if (StringUtils.isNotEmpty(messageId)) {
                message.setId(messageId);
            }
            String messageName = getValueAsString(PROPERTY_MESSAGE_DEFINITION_NAME, messageNode);
            if (StringUtils.isNotEmpty(messageName)) {
                message.setName(messageName);
            }
            String messageItemRef = getValueAsString(PROPERTY_MESSAGE_DEFINITION_ITEM_REF, messageNode);
            if (StringUtils.isNotEmpty(messageItemRef)) {
                message.setItemRef(messageItemRef);
            }

            if (StringUtils.isNotEmpty(messageId)) {
                element.addMessage(message);
            }
        }
    }

    public static void parseEventListeners(JsonNode listenersNode, Process process) {
        if (listenersNode == null) {
            return;
        }
        listenersNode = validateIfNodeIsTextual(listenersNode);
        for (JsonNode listenerNode : listenersNode) {
            JsonNode eventsNode = listenerNode.get(PROPERTY_EVENTLISTENER_EVENTS);
            if (eventsNode != null && eventsNode.isArray() && eventsNode.size() > 0) {

                EventListener listener = new EventListener();
                StringBuilder eventsBuilder = new StringBuilder();
                for (JsonNode eventNode : eventsNode) {
                    JsonNode eventValueNode = eventNode.get(PROPERTY_EVENTLISTENER_EVENT);
                    if (eventValueNode != null && !eventValueNode.isNull() && StringUtils.isNotEmpty(eventValueNode.asText())) {
                        if (eventsBuilder.length() > 0) {
                            eventsBuilder.append(",");
                        }
                        eventsBuilder.append(eventValueNode.asText());
                    }
                }

                if (eventsBuilder.length() == 0) {
                    continue;
                }

                listener.setEvents(eventsBuilder.toString());

                JsonNode rethrowEventNode = listenerNode.get("rethrowEvent");
                if (rethrowEventNode != null && rethrowEventNode.asBoolean()) {
                    JsonNode rethrowTypeNode = listenerNode.get("rethrowType");
                    if (rethrowTypeNode != null) {
                        if ("error".equalsIgnoreCase(rethrowTypeNode.asText())) {
                            String errorCode = getValueAsString("errorcode", listenerNode);
                            if (StringUtils.isNotEmpty(errorCode)) {
                                listener.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_THROW_ERROR_EVENT);
                                listener.setImplementation(errorCode);
                            }

                        } else if ("message".equalsIgnoreCase(rethrowTypeNode.asText())) {
                            String messageName = getValueAsString("messagename", listenerNode);
                            if (StringUtils.isNotEmpty(messageName)) {
                                listener.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_THROW_MESSAGE_EVENT);
                                listener.setImplementation(messageName);
                            }

                        } else if ("signal".equalsIgnoreCase(rethrowTypeNode.asText())) {
                            String signalName = getValueAsString("signalname", listenerNode);
                            if (StringUtils.isNotEmpty(signalName)) {
                                listener.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_THROW_SIGNAL_EVENT);
                                listener.setImplementation(signalName);
                            }

                        } else if ("globalSignal".equalsIgnoreCase(rethrowTypeNode.asText())) {
                            String signalName = getValueAsString("signalname", listenerNode);
                            if (StringUtils.isNotEmpty(signalName)) {
                                listener.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_THROW_GLOBAL_SIGNAL_EVENT);
                                listener.setImplementation(signalName);
                            }
                        }
                    }

                    if (StringUtils.isEmpty(listener.getImplementation())) {
                        continue;
                    }

                } else {

                    if (StringUtils.isNotEmpty(getValueAsString(PROPERTY_EVENTLISTENER_CLASS_NAME, listenerNode))) {
                        listener.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_CLASS);
                        listener.setImplementation(getValueAsString(PROPERTY_EVENTLISTENER_CLASS_NAME, listenerNode));

                    } else if (StringUtils.isNotEmpty(getValueAsString(PROPERTY_EVENTLISTENER_DELEGATE_EXPRESSION, listenerNode))) {
                        listener.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_DELEGATEEXPRESSION);
                        listener.setImplementation(getValueAsString(PROPERTY_EVENTLISTENER_DELEGATE_EXPRESSION, listenerNode));
                    }

                    if (StringUtils.isNotEmpty(getValueAsString(PROPERTY_EVENTLISTENER_ENTITY_TYPE, listenerNode))) {
                        listener.setEntityType(getValueAsString(PROPERTY_EVENTLISTENER_ENTITY_TYPE, listenerNode));
                    }

                    if (StringUtils.isEmpty(listener.getImplementation())) {
                        continue;
                    }
                }

                process.getEventListeners().add(listener);
            }
        }
    }

    public static String lookForSourceRef(String flowId, JsonNode childShapesNode) {
        String sourceRef = null;

        if (childShapesNode != null) {

            for (JsonNode childNode : childShapesNode) {
                JsonNode outgoingNode = childNode.get(EDITOR_TARGET);
                if (outgoingNode != null && outgoingNode.size() > 0) {
                    for (JsonNode outgoingChildNode : outgoingNode) {
                        JsonNode resourceNode = outgoingChildNode.get(EDITOR_SHAPE_ID);
                        if (resourceNode != null && flowId.equals(resourceNode.asText())) {
                            sourceRef = BpmnJsonConverterUtil.getElementId(childNode);
                            break;
                        }
                    }

                    if (sourceRef != null) {
                        break;
                    }
                }
                sourceRef = lookForSourceRef(flowId, childNode.get(EDITOR_CHILD_SHAPES));

                if (sourceRef != null) {
                    break;
                }
            }
        }
        return sourceRef;
    }

    public static List<ValuedDataObject> convertJsonToDataProperties(JsonNode objectNode, BaseElement element) {
        List<ValuedDataObject> dataObjects = new ArrayList<ValuedDataObject>();

        if (objectNode != null) {
            if (objectNode.isValueNode() && StringUtils.isNotEmpty(objectNode.asText())) {
                try {
                    objectNode = objectMapper.readTree(objectNode.asText());
                } catch (Exception e) {
                    logger.info("Data properties node cannot be read", e);
                }
            }

            JsonNode itemsArrayNode = objectNode.get(EDITOR_PROPERTIES_GENERAL_ITEMS);
            if (itemsArrayNode != null) {
                for (JsonNode dataNode : itemsArrayNode) {

                    JsonNode dataIdNode = dataNode.get(PROPERTY_DATA_ID);
                    if (dataIdNode != null && StringUtils.isNotEmpty(dataIdNode.asText())) {
                        ValuedDataObject dataObject = null;
                        ItemDefinition itemSubjectRef = new ItemDefinition();
                        String dataType = dataNode.get(PROPERTY_DATA_TYPE).asText();

                        if (dataType.equals("string")) {
                            dataObject = new StringDataObject();
                        } else if (dataType.equals("int")) {
                            dataObject = new IntegerDataObject();
                        } else if (dataType.equals("long")) {
                            dataObject = new LongDataObject();
                        } else if (dataType.equals("double")) {
                            dataObject = new DoubleDataObject();
                        } else if (dataType.equals("boolean")) {
                            dataObject = new BooleanDataObject();
                        } else if (dataType.equals("datetime")) {
                            dataObject = new DateDataObject();
                        } else {
                            logger.error("Error converting {}", dataIdNode.asText());
                        }

                        if (null != dataObject) {
                            dataObject.setId(dataIdNode.asText());
                            dataObject.setName(dataNode.get(PROPERTY_DATA_NAME).asText());

                            itemSubjectRef.setStructureRef("xsd:" + dataType);
                            dataObject.setItemSubjectRef(itemSubjectRef);

                            if (dataObject instanceof DateDataObject) {
                                try {
                                    dataObject.setValue(dateTimeFormatter.parseDateTime(dataNode.get(PROPERTY_DATA_VALUE).asText()).toDate());
                                } catch (Exception e) {
                                    logger.error("Error converting {}", dataObject.getName(), e);
                                }
                            } else {
                                dataObject.setValue(dataNode.get(PROPERTY_DATA_VALUE).asText());
                            }

                            dataObjects.add(dataObject);
                        }
                    }
                }
            }
        }
        return dataObjects;
    }

    public static void convertDataPropertiesToJson(List<ValuedDataObject> dataObjects, ObjectNode propertiesNode) {
        ObjectNode dataPropertiesNode = objectMapper.createObjectNode();
        ArrayNode itemsNode = objectMapper.createArrayNode();

        for (ValuedDataObject dObj : dataObjects) {
            ObjectNode propertyItemNode = objectMapper.createObjectNode();
            propertyItemNode.put(PROPERTY_DATA_ID, dObj.getId());
            propertyItemNode.put(PROPERTY_DATA_NAME, dObj.getName());

            String itemSubjectRefQName = dObj.getItemSubjectRef().getStructureRef();
            // remove namespace prefix
            String dataType = itemSubjectRefQName.substring(itemSubjectRefQName.indexOf(':') + 1);
            propertyItemNode.put(PROPERTY_DATA_TYPE, dataType);

            Object dObjValue = dObj.getValue();
            String value = new String();
            if (null == dObjValue) {
                propertyItemNode.put(PROPERTY_DATA_VALUE, "");
            } else {
                if ("datetime".equals(dataType)) {
                    value = new DateTime(dObjValue).toString("yyyy-MM-dd'T'hh:mm:ss");
                } else {
                    value = new String(dObjValue.toString());
                }
                propertyItemNode.put(PROPERTY_DATA_VALUE, value.toString());
            }

            itemsNode.add(propertyItemNode);
        }

        dataPropertiesNode.set(EDITOR_PROPERTIES_GENERAL_ITEMS, itemsNode);
        propertiesNode.set("dataproperties", dataPropertiesNode);
    }

    public static JsonNode validateIfNodeIsTextual(JsonNode node) {
        if (node != null && !node.isNull() && node.isTextual() && StringUtils.isNotEmpty(node.asText())) {
            try {
                node = validateIfNodeIsTextual(objectMapper.readTree(node.asText()));
            } catch (Exception e) {
                logger.error("Error converting textual node", e);
            }
        }
        return node;
    }

    public static boolean getValueAsBoolean(String name, JsonNode objectNode) {
        boolean propertyValue = false;
        JsonNode propertyNode = objectNode.get(name);
        if (propertyNode != null && !propertyNode.isNull()) {
            propertyValue = propertyNode.asBoolean();
        }
        if (propertyValue == false) {
            if (!Strings.isNullOrEmpty(objectNode.get(name).asText()) && objectNode.get(name).asText().equals("1")) {
                propertyValue = true;
            }
        }
        return propertyValue;
    }

    public static String getValueAsString(String name, JsonNode objectNode) {
        String propertyValue = null;
        JsonNode propertyNode = objectNode.get(name);
        if (propertyNode != null && !propertyNode.isNull()) {
            propertyValue = propertyNode.asText();
            if (Strings.isNullOrEmpty(propertyValue)) {
                if (propertyNode.size() > 0) {
                    StringBuffer stringBuffer = new StringBuffer();
                    for (JsonNode jsonNode : propertyNode) {
                        if (!Strings.isNullOrEmpty(jsonNode.asText())) {
                            if (stringBuffer.length() == 0) {
                                stringBuffer.append(jsonNode.asText());
                            } else {
                                stringBuffer.append("," + jsonNode.asText());
                            }
                        }
                    }
                    propertyValue = stringBuffer.toString();
                }
            }
        }
        return propertyValue;
    }

    public static String getPropertyValueAsString(String name, JsonNode objectNode) {
        String propertyValue = null;
        JsonNode propertyNode = getProperty(name, objectNode);
        if (propertyNode != null && propertyNode.isNull() == false) {
            propertyValue = propertyNode.asText();
        }
        return propertyValue;
    }

    public static JsonNode getProperty(String name, JsonNode objectNode) {
        JsonNode propertyNode = null;
        if (objectNode.get(EDITOR_SHAPE_PROPERTIES) != null) {
            JsonNode propertiesNode = objectNode.get(EDITOR_SHAPE_PROPERTIES);
            propertyNode = propertiesNode.get(name);
        }
        return propertyNode;
    }

    protected static int convertBooleanToIntJson(Boolean b) {
        if (b != null && b) {
            return 1;
        } else {
            return 0;
        }
    }

}
